/****************************** Module Header ******************************\
 * Module Name:  FileHelper.cs
 * Module Version:  1.0.0 (2011-11-1)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to operate the file or the directory. It supplies some
 * public method to move a folder,copy a folder,replace a file and so on.
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Linq;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;

namespace UCF.Core
{
    /// <summary>
    /// 文件/目录操作类
    /// <para>提供替换文件内容、复制目录、移动目录、获取路径名称等方法</para>
    /// </summary>
    public class FileHelper
    {
        public static string Charset { get; set; }
        #region 文件操作
        /// <summary>
        /// 将内容输出到文件中
        /// </summary>
        /// <param name="Contents">字串内容</param>
        /// <param name="FilePath">文件路径</param>
        public static void SaveAsFile(string Contents, string FilePath)
        {
            FolderExists(FilePath, true);
            File.WriteAllText(FilePath, Contents, Encoding.UTF8);
        }

        /// <summary>
        /// 检测文件是否存在
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool FileExists(string path)
        {
            return File.Exists(path);
        }
        /// <summary>
        /// 批量替换文件夹下面的文件中的指定内容
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="oldText"></param>
        /// <param name="newText"></param>
        /// <param name="count">文件数量计数器</param>
        /// <param name="recursive">是否递归所有子文件夹</param>
        /// <param name="search">搜索条件，如"*.*"</param>
        public static void ReplaceFilesText(string dirPath, string[] oldText, string[] newText, ref int count, bool recursive, string search = "*.*")
        {
            string[] arrFiles = Directory.GetFiles(dirPath, search);
            foreach (string strFile in arrFiles)
            {
                ReplaceFileText(strFile, oldText, newText);
                count++;
            }
            if (!recursive) return;

            string[] arrSubDirs = Directory.GetDirectories(dirPath);
            foreach (string strFolder in arrSubDirs)
            {
                ReplaceFilesText(strFolder, oldText, newText, ref count, recursive, search);
            }
        }
        /// <summary>
        /// 打开一个文件并替换文件中指定的内容
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="oldText"></param>
        /// <param name="newText"></param>
        public static void ReplaceFileText(string filePath, string[] oldText, string[] newText)
        {
            string strText = File.ReadAllText(filePath);
            int i = 0;
            foreach (string strOld in oldText)
            {
                strText = strText.Replace(strOld, newText[i]);
                i++;
            }
            File.WriteAllText(filePath, strText);
        }
        /// <summary>
        /// 获取指定文件夹下的所有文件的数组
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="getFullName"></param>
        /// <param name="searchSubFolders"></param>
        /// <param name="allowExtension">允许的扩展名，格式如：jpg,png,txt</param>
        /// <returns></returns>
        public static string[] GetFiles(string filePath, bool getFullName, bool searchSubFolders, string[] allowExtension = null)
        {
            if (!Directory.Exists(filePath)) return null;
            DirectoryInfo di = new DirectoryInfo(filePath);
            FileInfo[] arrFileInfos;
            IList<string> lstFiles = new List<string>();
            // "(*.*)|*.*|(.wav)|*.wav"
            if (allowExtension == null)
            {
                arrFileInfos = searchSubFolders ? di.GetFiles("*.*", SearchOption.AllDirectories) : di.GetFiles();
                foreach (FileInfo fi in arrFileInfos)
                {
                    lstFiles.Add(getFullName ? fi.FullName : fi.Name);
                }
            }
            else
            {
                foreach (string ext in allowExtension)
                {
                    arrFileInfos = searchSubFolders ? di.GetFiles("*." + ext, SearchOption.AllDirectories) : di.GetFiles("*." + ext);
                    foreach (FileInfo fi in arrFileInfos)
                    {
                        lstFiles.Add(getFullName ? fi.FullName : fi.Name);
                    }
                }
            }
            return lstFiles.ToArray();
        }
        /// <summary>
        /// 获取指定文件夹下的所有文件的数组
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="getFullName"></param>
        /// <returns></returns>
        public static string[] GetFiles(string filePath, bool getFullName = false)
        {
            return GetFiles(filePath, getFullName, false);
        }
        /// <summary>
        /// 删除路径
        /// </summary>
        /// <param name="path"></param>
        public static void DeletePath(string path)
        {
            if (Path.GetExtension(path).Length > 0)
            {
                File.Delete(path);
            }
            else
            {
                Directory.Delete(path);
            }
        }
        /// <summary>
        /// 读取文件中的文本
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ReadAllText(string path)
        {
            if (!File.Exists(path)) return "";
            return File.ReadAllText(path);
        }
        /// <summary>
        /// 读取指定行数的文本
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fromline"></param>
        /// <param name="toline"></param>
        /// <returns></returns>
        public static string[] ReadLines(string path, int fromline = 0, int toline = 0)
        {
            if (!File.Exists(path)) return null;
            if (toline == 0) return File.ReadAllLines(path);

            IList<string> list = new List<string>();
            int i = fromline;
            foreach (string s in File.ReadLines(path))
            {
                if (i > toline) break;
                list.Add(s);
                i++;
            }
            return list.ToArray();
        }
        #endregion
        #region 目录操作

        /// <summary>
        /// 移动文件夹
        /// </summary>
        /// <param name="fromDir"></param>
        /// <param name="toDir"></param>
        public static void MoveFolder(string fromDir, string toDir)
        {
            DirectoryInfo di = new DirectoryInfo(fromDir);
            toDir += "\\" + di.Name;
            di.MoveTo(toDir);
        }

        /// <summary>
        /// 复制文件夹
        /// </summary>
        /// <param name="fromDir"></param>
        /// <param name="toDir"></param>
        public static void CopyFolder(string fromDir, string toDir)
        {
            Directory.CreateDirectory(toDir);
            string[] files = Directory.GetFiles(fromDir);
            string[] subDirs = Directory.GetDirectories(fromDir);
            string strToFile;
            string strToDir;
            foreach (string strFile in files)
            {
                strToFile = toDir + "\\" + Path.GetFileName(strFile);
                File.Copy(strFile, strToFile, true);
            }
            foreach (string strDir in subDirs)
            {
                strToDir = toDir + "\\" + GetLastDirectoryName(strDir);
                CopyFolder(strDir, strToDir);
            }
        }
        /// <summary>
        /// 获取路径中最后一个目录名称
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetLastDirectoryName(string path)
        {
            return path.Substring(path.LastIndexOf('\\') + 1);
        }

        /// <summary>
        /// 获取指定路径的目录信息
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetDirectoryName(string path)
        {
            return Path.GetDirectoryName(path);
        }
        /// <summary>
        /// 检测目录是否存在
        /// </summary>
        /// <param name="path"></param>
        /// <param name="isCreating"></param>
        /// <returns></returns>
        public static bool FolderExists(string path, bool isCreating = true)
        {
            if (Path.HasExtension(path)) path = Path.GetDirectoryName(path);
            if (Directory.Exists(path)) return true;
            if (isCreating) Directory.CreateDirectory(@path);
            return false;
        }
        /// <summary>
        /// 打开目录
        /// </summary>
        /// <param name="path"></param>
        public static void OpenFolder(string path)
        {
            System.Diagnostics.Process.Start(path);
        }
        /// <summary>
        /// 创建目录
        /// </summary>
        /// <param name="path"></param>
        public static void CreateFolder(string path)
        {
            if (Directory.Exists(path)) return;
            Directory.CreateDirectory(path);
        }
        /// <summary>
        /// 获取最后一节路径名称
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetLastGetDirectoryName(string path)
        {
            if (path.IndexOf('\\') == -1) return path;
            return path.Substring(path.LastIndexOf('\\') + 1);
        }

        #endregion
        #region Web静态化操作

        /// <summary>
        /// 检测静态文件是否存在
        /// </summary>
        /// <param name="fromUri"></param>
        /// <param name="toUri"></param>
        /// <param name="builderUri"></param>
        /// <param name="timeDiff"></param>
        /// <returns></returns>
        public static string GetStaticPageURL(string fromUri, string toUri, string builderUri, double timeDiff = -30)
        {
            string toPath = System.Web.HttpContext.Current.Server.MapPath("Default.html");
            if (!File.Exists(toPath) || (File.GetLastWriteTime(toPath) < DateTime.Now.AddMinutes(timeDiff)))
            {
                return string.Format(builderUri, System.Web.HttpContext.Current.Server.UrlEncode(fromUri));
            }
            return toUri;
        }

        /// <summary>
        /// 生成静态页面
        /// </summary>
        /// <param name="exeUrl"></param>
        /// <param name="staticUrl"></param>
        public static void CreateStaticPage(string exeUrl, string staticUrl)
        {
            StreamWriter sw = new StreamWriter(System.Web.HttpContext.Current.Server.MapPath(staticUrl), false, Encoding.UTF8);
            System.Web.HttpContext.Current.Server.Execute(exeUrl, sw);
            sw.Close();
        }
        #endregion

        /// <summary>
        /// 更改文件名
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static string ChangeFileName(string filepath, string filename)
        {
            return string.Format("{0}\\{1}", Path.GetDirectoryName(filepath), filename);
        }


        public static void CopyFile(string fromfilepath, string tofilepath)
        {
            if (!File.Exists(fromfilepath)) return;
            string toFolder = Path.GetDirectoryName(tofilepath);
            if (!Directory.Exists(toFolder)) Directory.CreateDirectory(toFolder);
            File.Copy(fromfilepath, tofilepath);
        }

        /// <summary>
        /// 更改文件名前缀
        /// </summary>
        /// <param name="path"></param>
        /// <param name="prefix"></param>
        /// <param name="isOnlyFileName"></param>
        /// <returns></returns>
        public static string AppendFileNamePrefix(string path, string prefix, bool isOnlyFileName = false)
        {
            string sName = Path.GetFileName(path);
            if (isOnlyFileName) return string.Format("{0}{1}", prefix, sName);
            return string.Format("{0}{1}{2}", Path.GetDirectoryName(path), prefix, sName);
        }

        /// <summary>
        /// 获取文件名
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string GetFileName(string path)
        {
            return Path.GetFileName(path);
        }

        /// <summary>
        /// 追加内容到文件中
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="path"></param>
        public static void AppendToFile(string msg, string path)
        {
            FolderExists(path, true);
            if (File.Exists(path))
            {
                File.WriteAllText(path, string.Format("{0}{1}", File.ReadAllText(path), msg));
            }
            else
            {
                File.WriteAllText(path, msg);
            }
        }

        #region 压缩解压


        /// <summary>
        /// 遍历目录
        /// </summary>
        /// <param name="di"></param>
        /// <param name="s"></param>
        /// <param name="crc"></param>
        /// <param name="rootpath"></param>
        /// <param name="diszipfolders">不压缩的目录</param>
        private void direct(DirectoryInfo di, ref ZipOutputStream s, Crc32 crc, string rootpath, string[] diszipfolders = null)
        {
            //DirectoryInfo di = new DirectoryInfo(filenames);
            DirectoryInfo[] dirs = di.GetDirectories("*");

            //遍历目录下面的所有的子目录
            foreach (DirectoryInfo dirNext in dirs)
            {
                if (diszipfolders != null)
                {
                    if (diszipfolders.Contains(dirNext.FullName)) continue;
                }
                //将该目录下的所有文件添加到 ZipOutputStream s 压缩流里面
                FileInfo[] a = dirNext.GetFiles();
                this.writeStream(ref s, a, crc, rootpath);

                //递归调用直到把所有的目录遍历完成
                direct(dirNext, ref s, crc, rootpath, diszipfolders);
            }
        }

        /// <summary>
        /// 获取文件流
        /// </summary>
        /// <param name="s"></param>
        /// <param name="a"></param>
        /// <param name="crc"></param>
        /// <param name="rootpath"></param>
        private void writeStream(ref ZipOutputStream s, FileInfo[] a, Crc32 crc, string rootpath)
        {
            foreach (FileInfo fi in a)
            {
                FileStream fs = fi.OpenRead();

                byte[] buffer = new byte[fs.Length];
                fs.Read(buffer, 0, buffer.Length);

                string file = fi.FullName;
                file = file.Replace(rootpath, "");

                ZipEntry entry = new ZipEntry(file);

                entry.DateTime = DateTime.Now;

                // set Size and the crc, because the information
                // about the size and crc should be stored in the header
                // if it is not set it is automatically written in the footer.
                // (in this case size == crc == -1 in the header)
                // Some ZIP programs have problems with zip files that don't store
                // the size and crc in the header.
                entry.Size = fs.Length;
                fs.Close();

                crc.Reset();
                crc.Update(buffer);

                entry.Crc = crc.Value;

                s.PutNextEntry(entry);
                s.Write(buffer, 0, buffer.Length);
            }
        }

        /// <summary>
        /// 压缩目录
        /// </summary>
        /// <param name="frompath"></param>
        /// <param name="topath"></param>
        /// <param name="diszipfolders">不压缩的目录</param>
        public void ZipFolder(string frompath, string topath, string[] diszipfolders = null)
        {
            if (!Directory.Exists(frompath)) return;
            Crc32 crc = new Crc32();
            ZipOutputStream s = new ZipOutputStream(File.Create(topath));

            s.SetLevel(6); // 0 - store only to 9 - means best compression

            DirectoryInfo di = new DirectoryInfo(frompath);
            FileInfo[] a = di.GetFiles();

            //压缩这个目录下的所有文件
            writeStream(ref s, a, crc, frompath);
            //压缩这个目录下子目录及其文件
            direct(di, ref s, crc, frompath, diszipfolders);

            s.Finish();
            s.Close();
        }

        /// <summary>
        /// 解压缩压缩文件
        /// </summary>
        /// <param name="frompath"></param>
        /// <param name="topath"></param>
        public void UnZip(string frompath, string topath)
        {
            UnZip(File.OpenRead(frompath), topath);
        }

        public void UnZip(byte[] file, string topath)
        {
            UnZip(new MemoryStream(file), topath);
        }
        /// <summary>
        /// 从文件流解压成文件
        /// </summary>
        /// <param name="stm"></param>
        /// <param name="topath"></param>
        public void UnZip(Stream stm, string topath)
        {
            ZipInputStream s = new ZipInputStream(stm);
            ZipEntry theEntry;
            string fileName;
            if (!topath.EndsWith("//")) topath += "//";
            string directoryName = Path.GetDirectoryName(topath);
            //生成解压目录
            if(directoryName!=null) Directory.CreateDirectory(directoryName);
            while ((theEntry = s.GetNextEntry()) != null)
            {
                fileName = Path.GetFileName(theEntry.Name);
                if (fileName != String.Empty)
                {
                    //如果文件的壓縮後的大小為0那麼說明這個文件是空的因此不需要進行讀出寫入
                    if (theEntry.CompressedSize == 0) break;
                    fileName = topath + theEntry.Name;
                    //解压文件到指定的目录
                    directoryName = Path.GetDirectoryName(fileName);
                    //建立下面的目录和子目录
                    if (directoryName != null) Directory.CreateDirectory(directoryName);

                    FileStream streamWriter = File.Create(fileName);

                    int size = 2048;
                    byte[] data = new byte[2048];
                    while (true)
                    {
                        size = s.Read(data, 0, data.Length);
                        if (size > 0)
                        {
                            streamWriter.Write(data, 0, size);
                        }
                        else
                        {
                            break;
                        }
                    }
                    streamWriter.Close();
                }
            }
            s.Close();
        }
        #endregion

        #region 备份还原
        /// <summary>
        /// 备份文件夹
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="zipfile"></param>
        /// <param name="diszipfolder"></param>
        public void BackupFolder(string folder, string zipfile, params string[] diszipfolder)
        {
            FileHelper.FolderExists(zipfile);
            this.ZipFolder(folder, zipfile, diszipfolder);
        }
        #endregion

        public static string[] GetSubFolders(string path)
        {
            return Directory.GetDirectories(path);
        }

        /// <summary>
        /// 移动或重归命名路径
        /// </summary>
        /// <param name="oldpath"></param>
        /// <param name="newpath"></param>
        public static void MovePath(string oldpath, string newpath)
        {
            if (Path.GetExtension(oldpath).Length > 0)
            {
                File.Move(oldpath, newpath);
            }
            else
            {
                Directory.Move(oldpath, newpath);
            }
        }
    }
}
